#!/usr/bin/python
# -*- coding: utf-8 -*-
import optparse
import os,sys
import codecs

from airulibs import TaskManager
from airulibs import HostManager

import airulibs.utility.gadget
from airulibs.utility.gadget import write_line_with_sep
from airulibs.utility.gadget import MultiWriter
from airulibs.utility import rar

   
    
def printItems(items, message='', format=''):
    if len(items) > 0:
        write_line_with_sep(sys.stdout, message)
        write_line_with_sep(sys.stdout, '#'*40)
        for i in items:
            linksLocation.write(i.format(format=format))
        write_line_with_sep(sys.stdout, '#'*40)
        
def printList(list, message = '', redirect=None):
    if len(list) > 0:
        write_line_with_sep(sys.stdout, message)
        write_line_with_sep(sys.stdout, '#'*40)
        for l in list:
            if redirect is None:
                write_line_with_sep(sys.stdout, l)
            else:
                redirect.write(l)
        write_line_with_sep(sys.stdout, '#'*40)
        
def parseAuth(auth):
    '''
    check input Auth
    '''
    user = ""
    pwd = ""
    if auth is not None:
        auth = auth.split(":")
        if len(auth) != 2:
            write_line_with_sep(sys.stderr, "It seem something wrong style with your auth input.")
            write_line_with_sep(sys.stderr, "I hope there's no colon symbol, because I use it to split user&pwd.")
            sys.exit(1)
        user = auth[0]
        pwd = auth[1]
        
    if user == "" or pwd == "":
        msg = 'Please input account.'
        write_line_with_sep(sys.stderr, msg)
        sys.exit(1)
        
    return user,pwd

def listFiles(host, format):
    write_line_with_sep(sys.stdout, "Here is a full filelist in your account:")
    write_line_with_sep(sys.stdout, '*'*40)
    printItems(host.getFileList(), format=format)
    printItems(host.getFolderList(), format=format)
    write_line_with_sep(sys.stdout, '*'*40)
    
def findFiles(host, files, format):
    host.existedFiles = host.find(filenames = files)
    printItems(host.existedFiles,\
               "Files found in MegaUpload Host are listed below:",\
               format)
    printList(files,\
              "Here are the files can't find in Host:")
    
def localFileList(args, filter=''):
    '''
    get local files to be upload
    '''
    filenames = []
    for a in args:
        if os.path.isdir(a) == True:
            filenames.extend(airulibs.utility.gadget.walkDir(a))
        elif os.path.isfile(a) == True:
            filenames.append(a)
    filenames = airulibs.utility.gadget.file_filter(filenames, filter)
    filenames.sort()
    return filenames

def rarFiles(files, options='', filter='', tmp_path=''):
    todel =[]
    rar_files = []
    for f in files:
        compressed = rar.rar(f, options, filter, tmp_path)
        if f not in compressed:
            todel.append(f)
        rar_files.extend(compressed)
    files.extend(rar_files)
    for td in todel:
        files.remove(td)
    un_duplicate = list(set(files))
    un_duplicate.sort()
    return un_duplicate

def get_file_ranges(file, splitsize):
    if splitsize == 0:
        return (None,)
    filesize = os.path.getsize(file)
    #note: the same blocksize as encode.py!
    blocksize = 1024*32
    range_length = blocksize
    ranges = []
    while True:
        if range_length > splitsize:
            break
        range_length += blocksize
    range_length -= blocksize
    start = 0
    end = min(filesize-1, range_length-1)
    count = 0
    while start < filesize:
        count += 1
        ranges.append((start, end, count))
        start = end + 1
        end += range_length
        end = min(end, filesize-1)
    if len(ranges) == 1:
        return (None,)
#    print(("splitsize: %d" % range_length))
    return ranges

class FinishNofity(object):
    def __init__(self, pool):
        self.pool = pool
        
    def TaskFinishNofity(self, taskid):
        write_line_with_sep(sys.stdout, 
                            "Transfer %s in %s" % \
                            (self.pool.tasks[taskid].file, self.pool.tasks[taskid].speed))

def RunAWholeProcess(host, options, args):
    ##-o,--outputformat
    if options.outputformat is None:
        options.outputformat = ''
    outputFormat = options.outputformat
    if os.path.isfile(outputFormat):
        outputFormat = open(outputFormat, 'r').read()
    
    filter = options.exclude or ''
    
    readfilelist = []
    if options.filelist:
        #args are txt filelist, read files path from them
        for arg in args:
            readfilelist.extend([line.strip() for line in codecs.open(arg, 'r', encoding='utf8').readlines() if line])
        args = readfilelist
        
    localFiles = []
    
    if options.maxsize is not None:
        maxsize = int(options.maxsize)
        localFiles = args #localFileList(args)
        large_files = []
        for lf in localFiles:
            if os.path.isdir(lf):
                large_files.append(lf)
                print(('omit folder:', lf))
                continue
            if os.path.getsize(lf) >= maxsize * 1024 * 1024:
                large_files.append(lf)
                print(('omit large:', lf))
                continue
        for lf in large_files:
            localFiles.remove(lf)
        if not localFiles:
            return
    
    localFiles = localFiles or args
    ##-r,--rar
    if options.rar == True :
        rar_options = ''
        rar_path = ''
        if options.rar_options is not None:
            rar_options = options.rar_options
        if options.rar_path is not None:
            rar_path = options.rar_path
        localFiles = rarFiles(localFiles, rar_options, filter, rar_path)
    
    #if args has been walked by rar module, replace args with the filelist 
    localFiles = localFiles or args
    #filter again for some unrar file
    localFiles = localFileList(localFiles, filter)
    
    localFiles.sort()
    printList(localFiles, message="Listing Files to be dealed...")

    ##-f,--find
    if options.find == True:
        findFiles(host, localFiles, outputFormat)
    
    ##-u, --upload  
    if options.upload == True:
        ##-c, --check
        if options.check == True:
            if host.existedFiles == []:
                host.existedFiles = host.find(filenames = localFiles)
                printItems(host.existedFiles, \
                           message = "Files list below exsit in MegaUpload Host, Program won't upload them.", \
                           format = outputFormat)
        
        #-t, --thread
        MAX_THREAD = 1
        if options.thread is not None:
            MAX_THREAD = int(options.thread)
        other_args = {}
        if options.description is not None:
            other_args['message'] = options.description.encode('utf-8')
        splitsize = 0
        if options.splitsize is not None:
            splitsize = int(options.splitsize)
        retry = 5
        if options.retry is not None:
            retry = int(options.retry)
            
        taskpool = TaskManager.TaskPool(maxRunningTask = MAX_THREAD)
        taskpool.addFinishListener(FinishNofity(taskpool).TaskFinishNofity)
        for f in localFiles:
            if os.path.isfile(f) != True:
                continue
            ranges = get_file_ranges(f, splitsize)
            for file_range in ranges:
                task = TaskManager.UploadTask(f, host, taskpool, other_args, file_range=file_range)                
                taskpool.addTask(task)
                taskpool.setStart([-1])
        taskpool.start()
        taskpool.join()
            
        #after upload
        host.newupload.sort()
        host.find(filenames = localFiles, filelist = host.newupload)
        printItems(host.newupload,\
                   "Files that uploaded successfully are listed below:",\
                   outputFormat)
        if localFiles:
            printList(localFiles,\
                      "Files failed to upload are listed below:", redirect=failedFilelist)
            #answer = raw_input("Press Enter to continue")
        
    ##-d, --folder
    if options.folder is not None:
        folderitem = host.createFolder(options.folder)
        if folderitem is None:
            write_line_with_sep(sys.stdout, "Folder doesn't exsit, and Program fails to create it")
        else:
            write_line_with_sep(sys.stdout, "Moving files to folder %s" % options.folder)
            host.moveto(host.newupload, folderitem)
            host.moveto(host.existedFiles, folderitem)
#            linksLocation.write("Folder link is:")
            linksLocation.write('(Folder)' + folderitem.format(outputFormat))
            
if __name__ == "__main__":
#    import platform
#    if 'windows' in platform.platform().lower():
#        import airulibs.utility.win32_unicode_argv
#        sys.argv = airulibs.utility.win32_unicode_argv.win32_unicode_argv()
#    else:
#        # covert utf8 to unicode in linux
#        sys.argv = [i.decode(sys.getfilesystemencoding(),'ignore') for i in sys.argv]
#        
        
    p = optparse.OptionParser(description='Upload/List/Find in File-Hosting',
                          usage='%prog [options] File/Dir [File/Dir...]')
    #basic params: module and auth
    group = optparse.OptionGroup(p, "Basic: module/auth, required!")    
    group.add_option('--module', '-m', action="store", help='host', dest="module")
    group.add_option('--auth', '-a', action="store", help='user:pwd', dest="auth") 
    p.add_option_group(group)   
    #params for file manager
    group = optparse.OptionGroup(p, "File Manager") 
    group.add_option('--list', '-l', action="store_true", help='list all the file in Megaupload host. ', dest="list")
    group.add_option('--check', '-c', action="store_true", help='check if files have been uploaded ', dest="check")
    group.add_option('--find', '-f', action="store_true", help='Get a full filelist from hosting, and find a few files\' link. Be careful! If your account has manymany files.', dest="find")
    group.add_option('--folder', '-d', action="store", help='Move to this folder after uploaded. Folder will be Create if it isn\'t exist.', dest="folder")
    p.add_option_group(group)  
    #params for connection
    group = optparse.OptionGroup(p, "Proxy Connection") 
    group.add_option('--proxy', action="store", help='set proxy for access webpage, but there is no effect for uploading', dest="proxy")
    group.add_option('--curl-proxy', action="store", help='set proxy for curl lib', dest="curl_proxy")
    p.add_option_group(group)  
    #params for upload    
    group = optparse.OptionGroup(p, "Upload Options")
    group.add_option('--thread', '-t', action="store", help='upload mutilthread count', dest="thread")
    group.add_option('--upload', '-u', action="store_true", help='upload somefiles host', dest="upload")
    group.add_option('--ftp', action="store_true", help='upload files using ftp', dest="ftp")
    group.add_option('--ftp-mirror', action="store", help='set ftp for eu/us mirrors', dest="fso_mirror")
    group.add_option('--wait-time', action="store", help='wait some seconds to get link, after filedata were sent', dest="waittime")
    group.add_option('--retry', action="store", help='retry times', dest="retry")
    p.add_option_group(group)  
    
    #params for files control
    group = optparse.OptionGroup(p, "Files Controlling")
    group.add_option('--filelist', action="store_true", help='read files from a txt filelist(should be utf8)', dest="filelist")
    group.add_option('--rename', action="store_true", help='tell the server to save file with other filename', dest="rename")
    group.add_option('--rar', '-r', action="store_true", help='rar file with presetting', dest="rar")
    group.add_option('--rar-option', action="store", help='custom rar setting', dest="rar_options")
    group.add_option('--rar-path', action="store", help='setting where to pack the files', dest="rar_path")
    group.add_option('--exclude', '-x', action="store", help='Exclued files not to upload', dest="exclude")
    group.add_option('--max-size', action="store", help='do not upload file larger than this size', dest="maxsize")
    group.add_option('--split-size', action="store", help='split a file according to the given size, this operation would not eat your disk space.', dest="splitsize")
    p.add_option_group(group)  
    #useless
    #other params
    group = optparse.OptionGroup(p, "Others")
    group.add_option('--description', action="store", help='description', dest="description")    
    group.add_option('--outputformat', '-o', action="store", help='Setting how to output link format, BBCode/HTML', dest="outputformat")
    group.add_option('--log', action="store", help='Output log to file', dest="log")
    group.add_option('--links', action="store", help='Save links to file', dest="links")
    group.add_option('--failedlist', action="store", help='Save file list which failed to upload', dest="fail")
    #group.add_option('--monitor', action="store_true", help='Monitor a folder, upload new added files', dest="monitor")
    p.add_option_group(group)  

    (options, args) = p.parse_args()
    
    ##-a,--auth
    user, pwd = parseAuth(options.auth)
    
    ##-m, --module
    host = HostManager.getHost(options.module, user, pwd)
    
    if host is None:
        print("Failed to initial host")
        answer = eval(input("Press Enter to exit"))
        sys.exit()
        
    if options.log is not None:
        hostlog = codecs.open(options.log, 'a+', encoding='utf8')
        host.setFhOut(MultiWriter(sys.stdout, hostlog))
        host.setFhErr(MultiWriter(sys.stderr, hostlog))
    else:
        host.setFhOut(MultiWriter(sys.stdout))
        host.setFhErr(MultiWriter(sys.stderr))
    
    if options.proxy is not None:
        host.set_proxy(options.proxy)    
    if options.curl_proxy is not None:
        host.set_curl_proxy(options.curl_proxy)   
        
    if options.fso_mirror is not None:
        host.add_other_params('mirror', options.fso_mirror)
        
    if host is None or not host.login():
#        answer = raw_input("Press Enter to exit")
        sys.exit()
           
    if options.rename:
        host.set_rename_func(host.rename_by_time_hash)  
        
    if options.waittime:
        host.set_wait_time(int(options.waittime))
    
    if options.ftp:
        host.set_upload_mode('ftp')
        
    global linksLocation
    linksLocation = MultiWriter(sys.stdout)
    if options.links is not None:
        linksLocation = MultiWriter(sys.stdout, codecs.open(options.links, 'a+', encoding='utf8'))          
    
    global failedFilelist
    failedFilelist = MultiWriter(sys.stdout)
    if options.fail is not None:
        failedFilelist = MultiWriter(sys.stdout, codecs.open(options.fail, 'a+', encoding='utf8'))          
    
    ##-o,--outputformat
    if options.outputformat is None:
        options.outputformat = ''
    outputFormat = options.outputformat
   
    ##-l,--list
    if options.list == True:
        listFiles(host, outputFormat)
        answer = input("Press Enter to exit")
        sys.exit()
        
    RunAWholeProcess(host, options, args)

#    answer = raw_input("Press Enter to exit")
